package socket

import (
	"gdfs-service/conf"
	"gdfs-service/db"
	"gdfs-service/logcat"
	"gdfs-service/utils"
	"log"
	"net"
	"time"
)

type TcpClient struct {
	Conn       *net.TCPConn
	ByteBuffer []byte
}

type TcpConn struct {
	Alive bool
	Conn  *net.TCPConn
}

var tcpconn = &TcpConn{
	Alive: false,
	Conn:  nil,
}

type TcpConfig struct {
	regip   string
	regport string
	webport string
	storeid string
	weight  int
}

var tcpconf = &TcpConfig{
	regip:   "",
	regport: "",
	webport: "",
	storeid: "",
	weight:  1,
}

var heartch = make(chan bool)
var uploadch = make(chan bool)

func GetConn() *TcpConn {
	return tcpconn
}

func NewTcpClient(buf []byte, conn *net.TCPConn) *TcpClient {
	return &TcpClient{
		Conn:       conn,
		ByteBuffer: buf,
	}
}

type Clientchannel func(c *TcpClient)

//创建客户端
func CreateConn(ip, port string) *net.TCPConn {
	conn, err := BuildTcpConn(ip, port)
	if err != nil {
		log.Println("###连接建立失败:", err)
		tcpconn.Alive = false
		tcpconn.Conn = nil
		time.Sleep(10 * time.Second)
		RunTcpConn(tcpconf.regip, tcpconf.regport, tcpconf.webport, tcpconf.storeid, tcpconf.weight)
		return nil
	}
	return conn
}

//创建连接
func BuildTcpConn(ip, port string) (*net.TCPConn, error) {
	addr, _ := net.ResolveTCPAddr("tcp4", ip+":"+port)
	//建立tcp连接
	conn, err := net.DialTCP("tcp4", nil, addr)
	if err != nil {
		return nil, err
	}
	return conn, nil
}

//创建客户端处理器
func MakeClientHandler(conn *net.TCPConn, buffersize int, c Clientchannel) {
	go func() {
		buf := make([]byte, buffersize)
		defer conn.Close()
		for {
			n, err := conn.Read(buf)
			if err != nil || n == 0 {
				logcat.Info("os,stdin err=", err, "or readlen == 0  reconn")
				tcpconn.Alive = false
				uploadch <- true
				heartch <- true
				//重连
				time.Sleep(10 * time.Second)
				logcat.Info("开始重连............")
				RunTcpConn(tcpconf.regip, tcpconf.regport, tcpconf.webport, tcpconf.storeid, tcpconf.weight)
				logcat.Info("close............")
				return
			}

			c(NewTcpClient(buf[:n], conn))
		}
	}()

}

func RunTcpConn(regip, regport, webport, storeid string, weight int) {
	tcpconf = &TcpConfig{
		regip:   regip,
		regport: regport,
		webport: webport,
		storeid: storeid,
		weight:  weight,
	}
	conn := CreateConn(regip, regport)
	//获取连接
	if conn != nil {
		tcpconn.Conn = conn
		tcpconn.Alive = true
		MakeClientHandler(conn, 6*1024*1024, ClientChannelHandler)
	} else {
		log.Println("连接为空")
		return
	}
	//上报服务信息
	uploadStoreInfo(conn, webport, storeid, weight)
	//定时发送心跳
	hearbeatTimer(conn)
	//定时上报系统信息
	uploadSystemInfo(conn)
}

//上报系统信息
func uploadSystemInfo(conn *net.TCPConn) {
	if conn != nil {
		//开始上报系统信息
		logcat.Info("###上报服务信息")
		data := GenerateUploadFileSysInfo(GetSystemInfo())
		conn.Write(data)
	}
	timer := time.NewTicker(time.Second * 10)
	go func() {
		for {
			select {
			case <-timer.C:
				if conn != nil {
					//开始上报系统信息
					data := GenerateUploadFileSysInfo(GetSystemInfo())
					conn.Write(data)
				}
			}
		}
	}()
}

func GetSystemInfo() UploadHardWareInfo {
	cpuPercent, cpuCount, cpuGhz := utils.GetCpuInfo()
	mPercent, mtotal, mused := utils.GetMemInfo()
	dPercent, dtotal, dused := utils.GetDiskInfo()
	sPercent, stotal, sused := utils.GetSwapInfo()
	var fileinfo db.FileInfo
	var filetotal int64
	db.GetDB().Find(&fileinfo).Count(&filetotal)
	var sysinfo UploadHardWareInfo
	sysinfo.StoreId = conf.GetStoreid()
	sysinfo.CpuGhz = cpuGhz
	sysinfo.CpuCount = cpuCount
	sysinfo.CpuPercent = cpuPercent
	sysinfo.DiskPercent = dPercent
	sysinfo.DiskUsed = int64(dused)
	sysinfo.DiskTotal = int64(dtotal)
	sysinfo.SwapPercent = sPercent
	sysinfo.SwapTotal = int64(stotal)
	sysinfo.SwapUsed = int64(sused)
	sysinfo.MemTotal = int64(mtotal)
	sysinfo.MemUsed = int64(mused)
	sysinfo.MemPercent = mPercent
	sysinfo.StoreFileCount = filetotal
	return sysinfo
}

//上报服务信息
func uploadStoreInfo(conn *net.TCPConn, webport, storeid string, weight int) {
	if conn != nil {
		//开始上报存储服务信息
		logcat.Info("###上报服务信息")
		data := GenerateUploadInfoCmd(weight, "", webport, storeid)
		conn.Write(data)
	}
	timer := time.NewTicker(time.Second * 60)
	go func() {
		for {
			select {
			case <-timer.C:
				if conn != nil {
					//开始上报存储服务信息
					data := GenerateUploadInfoCmd(weight, "", webport, storeid)
					conn.Write(data)
				}
			case stop := <-uploadch:
				if stop {
					timer.Stop()
					return
				}

			}
		}
	}()
}

//客户端心跳定时器
func hearbeatTimer(conn *net.TCPConn) {
	if conn != nil {
		logcat.Info("###发送心跳")
		data := GenerateHeartBeatCmd()
		conn.Write(data)
	}
	timer := time.NewTicker(time.Second * 30)
	go func() {
		for {
			select {
			case <-timer.C:
				if conn != nil {
					logcat.Info("###发送心跳")
					data := GenerateHeartBeatCmd()
					conn.Write(data)
				}
			case stop := <-heartch:
				if stop {
					timer.Stop()
					return
				}

			}
		}
	}()
}
